use std::marker::PhantomData;
use std::mem::forget;
use std::ops::{Deref, DerefMut};
use std::sync::{Mutex, Once};
use std::time::Duration;

use crate::to_mut_ref;
use crate::utils::thread_pool::MultiThreadTester;
use crate::utils::ThreadSafePtr;

///实现一个简易延迟闭包，可以暂时缓存结果(生命周期等同于内部生命周期)
pub struct CacheCap<T> {
    val: Option<T>,
    get_val: Box<dyn Fn() -> T + Sync + Send + 'static>,
    once: Option<Once>,
}

impl<T> DerefMut for CacheCap<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.visit_mut()
    }
}

impl<T> Deref for CacheCap<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.visit()
    }
}

impl<T> CacheCap<T> {
    pub fn of(func: impl Fn() -> T + Send + Sync + 'static) -> Self {
        CacheCap {
            val: None,
            get_val: Box::new(func),
            once: Some(Once::new()),
        }
    }
    pub fn of_sync(func: impl Fn() -> T + Sync + Send + 'static) -> Self {
        CacheCap {
            val: None,
            get_val: Box::new(func),
            once: None,
        }
    }
    fn call_once(&mut self) -> &mut Self {
        if self.val.is_none() {
            let this = to_mut_ref!(self, Self);
            if let Some(once) = this.once.as_mut() {
                once.call_once(|| {
                    this.val.replace(this.get_val.as_ref()());
                });
            } else {
                if self.val.is_none() {
                    this.val.replace(this.get_val.as_ref()());
                }
            }
        }
        self
    }

    pub fn visit(&self) -> &T {
        to_mut_ref!(self, Self).call_once().val.as_ref().unwrap()
    }

    pub fn visit_mut(&self) -> &mut T {
        to_mut_ref!(self, Self).call_once().val.as_mut().unwrap()
    }

    pub fn get(mut self) -> T {
        self.call_once();
        self.val.take().unwrap()
    }
}

// #[test]
// fn test() {
//     thread_safe_ptr! {
//         let msg = String::from("ok");
//     }
//     let cap = CacheCap::of(move || "yes ".to_owned());
//     let cap = ThreadSafePtr::capture(&cap);
//     let mut tester = MultiThreadTester::new();
//     tester.append_test(
//         "shit",
//         move || {
//             println!("{}", cap.visit());
//         },
//         100,
//     );
//     tester.run();
//
// }
